package com.corpgovernment.common.requestprocess;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
import java.util.StringJoiner;

import com.ctrip.corp.obt.generic.utils.JsonUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * @author dlz
 * @since 2024/2/23
 */
@Slf4j
public abstract class BaseRemoteEventSubscriber<E> {

    public void onEvent(E event) {
        try {
            // 初始化日志上下文
            LogContextUtil.initContext();
            LogContextUtil.setActionName(getActionName());
            LogContextUtil.setStartTime(LocalDateTime.now());

            // 处理event
            onEvent0(event);

        } catch (Exception e) {
            // 处理未知异常
            LogContextUtil.setServerException(e);
            throw e;
        } finally {
            // 响应日志埋点
            eventLogMetric(event);
            // 移除日志上下文
            LogContextUtil.remove();
        }
    }

    protected abstract void onEvent0(E event);

    /**
     * 获取消费的event名
     * 例如SettlementBatchCloseEvent
     */
    public abstract String getActionName();

    /**
     * 记录日志埋点
     */
    private void eventLogMetric(E event) {
        try {
            // 埋点处理
            doMetric(event);
        } catch (Throwable e) {
            log.error(getActionName() + "埋点失败", e);
        }
        try {
            // 日志处理
            doLog(event);
        } catch (Throwable e) {
            log.error(getActionName() + "日志记录失败", e);
        }
    }

    /**
     * 执行响应埋点
     */
    private void doMetric(E event) {
        MetricUtil.build(getMetricPrefix() + "." + getActionName())
            .tag("errorCode", LogContextUtil.getCorpBusinessExceptionCode())
            .tag("exceptionName", LogContextUtil.getServerExceptionName())
            .tag(getMetricTag(event))
            .recordByTimer(LogContextUtil.getDuration());
    }

    /**
     * 获取埋点指标前缀,例如settlement.event
     */
    protected abstract String getMetricPrefix();

    /**
     * 执行日志
     */
    private void doLog(E event) {
        StringJoiner sj = new StringJoiner(System.lineSeparator());
        sj.add("消费event名==>" + getActionName());
        sj.add("event内容==>" + JsonUtils.toJsonString(event));

        if (LogContextUtil.getServerException() != null) {
            log.error(sj.toString(), LogContextUtil.getServerException());
        } else {
            log.info(sj.toString());
        }
    }

    /**
     * 获得埋点tag
     */
    protected Map<String, String> getMetricTag(E event) {
        return Collections.emptyMap();
    }
}
